/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufg.inf.si.poo.formula1.Simulator;

import br.ufg.inf.si.poo.formula1.Driver.Driver;
import br.ufg.inf.si.poo.formula1.Library.Library;
import br.ufg.inf.si.poo.formula1.Race.GridPosition;
import br.ufg.inf.si.poo.formula1.Race.GridRace;
import br.ufg.inf.si.poo.formula1.Race.Race;
import java.util.Random;

/**
 * SimulatorGridRace
 * 
 * Versao 1.0
 * 
 * Data 26/01/2013
 * 
 * @author Igor
 */
public class SimulatorGridRace {
    //Construtores
    private SimulatorGridRace(){}

    //Outros Metodos
    /**
     * Simula as voltas de cada piloto, levando em consideração os acidentes
     * @param gridRace 
     */
    public static void generateTimes(Race race){
        if (race.getGridRace().getGridRace()[0] != null) {
            int qttLapsCircuit = race.getGridRace().getGridRace()[0].getQttLapsCircuit();
            int[][] Accident = SimulatorGridRace.generateAccident(qttLapsCircuit, race.getGridRace().getQttDrivers());
            long timeDriverFastestLap = 80000; //Inicializo com o valor maximo
            Driver driverDriverFastestLap = null;

            for (int i = 0; i < qttLapsCircuit; i++) {
                for (int j = 0; j < race.getGridRace().getQttDrivers(); j++) {
                    if (SimulatorGridRace.velidateAccident(Accident, i, j)) {
                        race.getGridRace().getGridRace()[j].setStatus("Accident");
                    }
                    if (!"Accident".equals(race.getGridRace().getGridRace()[j].getStatus())
                            && !"DNQ".equals(race.getGridRace().getGridRace()[j].getStatus())) {
                        race.getGridRace().getGridRace()[j].getTimeLap()[i] = Library.generatesTime();
                        race.getGridRace().getGridRace()[j].setQttLapsRace(race.getGridRace().getGridRace()[j].getQttLapsRace() + 1);
                        race.getCircuit().setLapRecordTime(race.getGridRace().getGridRace()[j].getTimeLap()[i], race.getGridRace().getGridRace()[j].getDriver().getDriverName(), race.getYear());

                        //Verifica o piloto que obteve a volta mais rapida
                        if (race.getGridRace().getGridRace()[j].getTimeLap()[i] < timeDriverFastestLap) {
                            timeDriverFastestLap = race.getGridRace().getGridRace()[j].getTimeLap()[i];
                            driverDriverFastestLap = race.getGridRace().getGridRace()[j].getDriver();
                        }
                    }
                }
            }
            SimulatorGridRace.orderDriversAfterGenerateTimes(race.getGridRace());

            //Incrementa a volta mais rapida para a equipe
            if (driverDriverFastestLap != null) {
                driverDriverFastestLap.getTeam().setFastesLaps(driverDriverFastestLap.getTeam().getFastesLaps() + 1);
            }
        }
    }

    /**
     * Ordena o grid apos a geração dos tempos de cada volta, ou seja, coloca os pilotos na posicao final
     * @param gridRace, é o grid da corrida a ser ordenado
     */
    private static void orderDriversAfterGenerateTimes(GridRace gridRace){
        for (int i = 0; i < gridRace.getQttDrivers() - 1; i++) {
            for (int j = i + 1; j < gridRace.getQttDrivers(); j++) {
                if (gridRace.getGridRace()[i].timeTotal() > gridRace.getGridRace()[j].timeTotal()
                        && !"DNQ".equals(gridRace.getGridRace()[j].getStatus())) {
                    GridPosition gridPosition = gridRace.getGridRace()[i];
                    gridRace.getGridRace()[i] = gridRace.getGridRace()[j];
                    gridRace.getGridRace()[j] = gridPosition;
                }
            }
        }
        
        /* Ordena e valida os acidentados */
        for (int i = 0; i < gridRace.getQttDrivers() - 1; i++) {
            for (int j = i + 1; j < gridRace.getQttDrivers(); j++) {
                if ("Accident".equals(gridRace.getGridRace()[i].getStatus())
                        && !"DNQ".equals(gridRace.getGridRace()[j].getStatus())) {
                    GridPosition gridPosition = gridRace.getGridRace()[i];
                    gridRace.getGridRace()[i] = gridRace.getGridRace()[j];
                    gridRace.getGridRace()[j] = gridPosition;
                }
            }
        }
        
        for (int i = 0; i < gridRace.getQttDrivers(); i++) {
            gridRace.getGridRace()[i].setPosition(i+1);
        }
        gridRace.updateDataDriversGridRace();
    }    

    /**
     * Gera em qual volta e quais pilotos sofrerao acidente
     * @param qttLapsCircuit, quantidade de voltas
     * @param qttDrivers, quantiade de pilotos
     * @return, vetor com a volta e o piloto que sofreu acidente
     */
    private static int[][] generateAccident(int qttLapsCircuit, int qttDrivers){
        Random random = new Random();
        /* Coloco para gerar um numero aleatoria de 0 ate 20, subtraio 10 e caso
         seja resultado negativo entao a qttAccident sera igual a zero, isso pq
         se deixar apenas de 0 a 10, sempre vai acontecer muitos acidentes, oque
         nao acontece na vida real */
        int qttAccident = random.nextInt(20) - 10;
        if(qttAccident < 0) {
            qttAccident = 0;
        }
        int[][] Accident = new int[10][2];

        for(int i = 0;i < 10;i++){
            if(i < qttAccident){
                Accident[i][0] = random.nextInt(qttLapsCircuit-1); //Lap
                Accident[i][1] = random.nextInt(qttDrivers-1); //Driver
            }else{
                Accident[i][0] = -1;
            }
        }

        return Accident;
    }
    
    /**
     * Verifica se o piloto sofrera acidente na volta especificada
     * @param Accident, matriz com acidentes previamente estabelecidos
     * @param lap, volta em que se encontra a corrida
     * @param driver, piloto atual
     * @return, true ou false se acontece acidente
     */
    private static boolean velidateAccident(int[][] Accident, int lap, int driver){
        for(int i = 0;i < 10;i++){
            if((Accident[i][0] == lap)&&(Accident[i][1] == driver)){
                return true;
            }
        }
        return false;
    }
}
